#include "UP_EXTI.h"
#include "UP_GPIO.h"
#include "UP_test.h"
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <stdint.h>

typedef struct {
    rcu_periph_enum rcu; // 按键端口时钟
    uint32_t gpio_port;  // 按键端口
    uint32_t gpio_pin;   // 按键引脚

    uint32_t exti_irqn; // 外部中断0
    uint32_t exti_port; // 外部中断端口资源
    uint32_t exti_pin;  // 外部中断引脚资源

    exti_line_enum exit_line; // 外部中断
} Pin_Config;

Pin_Config getPinConfig(UP_GPIO uc_gpio)
{
    Pin_Config config;
    config.rcu       = uc_gpio.rcu_gpio;
    config.gpio_port = uc_gpio.port;
    config.gpio_pin  = uc_gpio.pin;

    /* 根据引脚名获取外部中断号 */

    switch (config.gpio_port) {
        case GPIOA:
            config.exti_port = EXTI_SOURCE_GPIOA;
            break;
        case GPIOB:
            config.exti_port = EXTI_SOURCE_GPIOB;
            break;
        case GPIOC:
            config.exti_port = EXTI_SOURCE_GPIOC;
            break;
        case GPIOD:
            config.exti_port = EXTI_SOURCE_GPIOD;
            break;
        case GPIOE:
            config.exti_port = EXTI_SOURCE_GPIOE;
            break;
        case GPIOF:
            config.exti_port = EXTI_SOURCE_GPIOF;
            break;
        case GPIOG:
            config.exti_port = EXTI_SOURCE_GPIOG;
            break;
        case GPIOH:
            config.exti_port = EXTI_SOURCE_GPIOH;
            break;
        case GPIOI:
            config.exti_port = EXTI_SOURCE_GPIOI;
            break;
        default:
            break;
    }

    switch (config.gpio_pin) {
        case GPIO_PIN_0:
            config.exti_irqn = EXTI0_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN0;
            config.exit_line = EXTI_0;
            break;
        case GPIO_PIN_1:
            config.exti_irqn = EXTI1_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN1;
            config.exit_line = EXTI_1;
            break;
        case GPIO_PIN_2:
            config.exti_irqn = EXTI2_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN2;
            config.exit_line = EXTI_2;
            break;
        case GPIO_PIN_3:
            config.exti_irqn = EXTI3_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN3;
            config.exit_line = EXTI_3;
            break;
        case GPIO_PIN_4:
            config.exti_irqn = EXTI4_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN4;
            config.exit_line = EXTI_4;
            break;
        case GPIO_PIN_5:
            config.exti_irqn = EXTI5_9_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN5;
            config.exit_line = EXTI_5;
            break;
        case GPIO_PIN_6:
            config.exti_irqn = EXTI5_9_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN6;
            config.exit_line = EXTI_6;
            break;
        case GPIO_PIN_7:
            config.exti_irqn = EXTI5_9_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN7;
            config.exit_line = EXTI_7;
            break;
        case GPIO_PIN_8:
            config.exti_irqn = EXTI5_9_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN8;
            config.exit_line = EXTI_8;
            break;
        case GPIO_PIN_9:
            config.exti_irqn = EXTI5_9_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN9;
            config.exit_line = EXTI_9;
            break;
        case GPIO_PIN_10:
            config.exti_irqn = EXTI10_15_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN10;
            config.exit_line = EXTI_10;
            break;
        case GPIO_PIN_11:
            config.exti_irqn = EXTI10_15_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN11;
            config.exit_line = EXTI_11;
            break;
        case GPIO_PIN_12:
            config.exti_irqn = EXTI10_15_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN12;
            config.exit_line = EXTI_12;
            break;
        case GPIO_PIN_13:
            config.exti_irqn = EXTI10_15_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN13;
            config.exit_line = EXTI_13;
            break;
        case GPIO_PIN_14:
            config.exti_irqn = EXTI10_15_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN14;
            config.exit_line = EXTI_14;
            break;
        case GPIO_PIN_15:
            config.exti_irqn = EXTI10_15_IRQn;
            config.exti_pin  = EXTI_SOURCE_PIN15;
            config.exit_line = EXTI_15;
            break;
        default:
            break;
    }

    return config;
}

/*!
    \brief     EXTI初始化, 可传入上下拉参数，中断优先级
    \param[in]  pin: 引脚
    \param[in]  pull_up_down: 初始上下拉参数
        \arg    GPIO_PUPD_NONE: 无上下拉
        \arg    GPIO_PUPD_PULLUP: 上拉
        \arg    GPIO_PUPD_PULLDOWN: 下拉
    \param[in]  trig_type: 触发类型
        \arg   EXTI_TRIG_RISING: 上升沿触发
        \arg   EXTI_TRIG_FALLING: 下降沿触发
        \arg   EXTI_TRIG_BOTH: 上升下降沿触发
    \param[in]  nvic_irq_pre_priority: 中断抢占优先级 0-3
    \param[in]  nvic_irq_sub_priority: 中断子优先级 0-3
    \param[out] none
    \retval     none

    模块依赖： rcu/gpio/exti/syscfg/misc
*/
extern void EXTI_init_with_params(UP_GPIO uc_gpio,
                                  uint32_t pull_up_down,
                                  uint32_t trig_type,
                                  uint8_t nvic_irq_pre_priority,
                                  uint8_t nvic_irq_sub_priority)
{
    // 设置中断优先级组  2位用于抢占优先级，2位用于响应优先级
    // nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

    /* 根据引脚名获取端口时钟、端口和引脚号 */

    Pin_Config config = getPinConfig(uc_gpio);

    rcu_periph_clock_enable(config.rcu); // 开启时钟
    rcu_periph_clock_enable(RCU_SYSCFG); // 系统配置时钟

    /* 配置为输入模式 下拉模式 */

    // 根据按键默认高低电平状态，配置上下拉
    gpio_mode_set(config.gpio_port, GPIO_MODE_INPUT, pull_up_down, config.gpio_pin);
    /* 使能NVIC中断 中断分组为2位抢占优先级，2位子优先级 需要 misc 模块支持 */
    nvic_irq_enable(config.exti_irqn, nvic_irq_pre_priority, nvic_irq_sub_priority); // 抢占优先级0-3，子优先级0-3
    /* 连接中断线到GPIO - 需要 syscfg 模块支持 */
    syscfg_exti_line_config(config.exti_port, config.exti_pin);
    /* 初始化中断线 */
    exti_init(config.exit_line, EXTI_INTERRUPT, trig_type);
    /* 使能中断 */
    exti_interrupt_enable(config.exit_line);
    /* 清除中断标志位 */
    exti_interrupt_flag_clear(config.exit_line);
}

// void EXTI_isr_handler(uint8_t exit_line_num)
// {
//     // 可将此方法复制到自己的main文件中，并保证本方法是注释掉的。两边不能同时存在。
//     // 如果要处理多个中断，可以在这里添加if或switch判断，然后调用不同的处理函数，例如：
//     // if (exit_line_num == 0)
//     // {
//     // }else if (exit_line_num == 1)
//     // {
//     // }
// }

/*!
    \brief  EXTI初始化, 默认下拉，中断优先级3, 上升下降沿触发
            Px0~Px15分别对应EXTI0~EXTI15
            例如：
                参数为PA0，则需要EXTI_isr_handler方法得到的参数exit_line_num 为 0
                参数为PB5，则需要EXTI_isr_handler方法得到的参数exit_line_num 为 5
                参数为PD2，则需要EXTI_isr_handler方法得到的参数exit_line_num 为 2

    \param[in]  pin: 引脚名称 例如：PA0, PB5, PD2
*/
void EXTI_init(UP_GPIO pin)
{
    EXTI_init_with_params(pin, GPIO_PUPD_PULLDOWN, EXTI_TRIG_BOTH, 3U, 3U);
}

#if TEST_TYPE == TEST_PWM || TEST_TYPE == TEST_EXTI
// void EX0_isr(){};
#else
void EX0_isr(){};
#endif

void EX1_isr(){};
void EX2_isr(){};
void EX3_isr(){};
void EX4_isr(){};
void EX5_isr(){};
void EX6_isr(){};
void EX7_isr(){};
void EX8_isr(){};
void EX9_isr(){};
void EX10_isr(){};
void EX11_isr(){};
void EX12_isr(){};
void EX13_isr(){};
void EX14_isr(){};
#if TEST_TYPE == TEST_DAC
// void EX15_isr(){};
#else
void EX15_isr(){};
#endif


void EXTI0_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_0)) {
        EX0_isr();
        exti_interrupt_flag_clear(EXTI_0);
    }
}
void EXTI1_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_1)) {
        EX1_isr();
        exti_interrupt_flag_clear(EXTI_1);
    }
}
void EXTI2_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_2)) {
        EX2_isr();
        exti_interrupt_flag_clear(EXTI_2);
    }
}
void EXTI3_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_3)) {
        EX3_isr();
        exti_interrupt_flag_clear(EXTI_3);
    }
}
void EXTI4_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_4)) {
        EX4_isr();
        exti_interrupt_flag_clear(EXTI_4);
    }
}
void EXTI5_9_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_5)) {
        EX5_isr();
        exti_interrupt_flag_clear(EXTI_5);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_6)) {
        EX6_isr();
        exti_interrupt_flag_clear(EXTI_6);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_7)) {
        EX7_isr();
        exti_interrupt_flag_clear(EXTI_7);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_8)) {
        EX8_isr();
        exti_interrupt_flag_clear(EXTI_8);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_9)) {
        EX9_isr();
        exti_interrupt_flag_clear(EXTI_9);
    }
}

void EXTI10_15_IRQHandler(void)
{
    if (RESET != exti_interrupt_flag_get(EXTI_10)) {
        EX10_isr();
        exti_interrupt_flag_clear(EXTI_10);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_11)) {
        EX11_isr();
        exti_interrupt_flag_clear(EXTI_11);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_12)) {
        EX12_isr();
        exti_interrupt_flag_clear(EXTI_12);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_13)) {
        EX13_isr();
        exti_interrupt_flag_clear(EXTI_13);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_14)) {
        EX14_isr();
        exti_interrupt_flag_clear(EXTI_14);
    }
    if (RESET != exti_interrupt_flag_get(EXTI_15)) {
        EX15_isr();
        exti_interrupt_flag_clear(EXTI_15);
    }
}
